package dbconnector.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.UUID;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.WriteResult;

import dbconnector.service.IServiceInfo;
import dbconnector.service.IServiceRegisterManager;

/**
 * Klasa odpowiadajaca za zarzadzanie (rejestrowanie/odrejestrowywanie) wpisami
 * reprezentujacymi uslugi kontenera
 * 
 */
public class ServiceRegisterManager implements IServiceRegisterManager {

	private DBCollection coll;

	public ServiceRegisterManager(DBCollection coll) {
		this.coll = coll;
	}

	public String registerService(IServiceInfo info) {
		String id = UUID.randomUUID().toString();
		registerService(id, info);
		return id;
	}

	// TODO - dodac rzucanie wyjatku jak blad zapisu
	@Override
	public void registerService(String id, IServiceInfo info) {
		BasicDBObject insertQuery = new BasicDBObject();

		insertQuery.put(ServiceInfoFieldsNames.ID, id);
		insertQuery.put(ServiceInfoFieldsNames.SERVICE_NAME, info.getServiceName());
		insertQuery.put(ServiceInfoFieldsNames.HOST, info.getHost());
		insertQuery.put(ServiceInfoFieldsNames.QUEUE_NAME, info.getQueueName());

		Dictionary<String, String> properties = info.getProperties();
		Enumeration<String> keys = info.getProperties().keys();
		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			insertQuery.put(key, properties.get(key));
		}
		// zapisanie aktualnego czasu
		insertQuery.put(ServiceInfoFieldsNames.TIME_STAMP, new Date());
		// wpisanie danych do bazy
		WriteResult writeResult = coll.insert(insertQuery);
		if (writeResult.getError() != null) {
			// return null;
			// TODO rzucanie wyjatku
		}
	}

	@Override
	public void unregisterService(String id) {
		DBObject query = new BasicDBObject();
		query.put(ServiceInfoFieldsNames.ID, id);
		coll.remove(query);
	}

	//	public List<IServiceInfo> getService(String serviceName, String filter) {
	@Override
	public List<IServiceInfo> getService(String serviceName, Dictionary<String, String> properties) {
		ArrayList<IServiceInfo> resultList = new ArrayList<IServiceInfo>();
		IServiceInfo tmpInfo;
		BasicDBObject query = new BasicDBObject();
		query.put(ServiceInfoFieldsNames.SERVICE_NAME, serviceName);

		Enumeration<String> keys = properties.keys();
		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			query.put(key, properties.get(key));
		}
		DBCursor cursor = coll.find(query);
		DBObject queryResult;
		try {
			while (cursor.hasNext()) {
				queryResult = cursor.next();
				tmpInfo = setServiceInfo(queryResult);
				resultList.add(tmpInfo);
			}
		} finally {
			cursor.close();
		}
		return resultList;
	}

	@Override
	public List<IServiceInfo> getService(String serviceName) {
		return getService(serviceName, new Hashtable<String, String>());
	}

	/**
	 * Tworzy obiekt typu IServiceInfo i parametryzuje go danymi z obiektu
	 * pobranego z bazy danych
	 * 
	 * @param queryResult
	 *            obiekt, z ktorego pobierane sa informacje
	 */
	IServiceInfo setServiceInfo(DBObject queryResult) {

		IServiceInfo info = new ServiceInfo();
		for (String key : queryResult.keySet()) {
			switch (key) {
			case ServiceInfoFieldsNames.ID:
				info.setId(((String) queryResult.get(key)).toString());
				break;
			case ServiceInfoFieldsNames.SERVICE_NAME:
				info.setServiceName((String) queryResult.get(key));
				break;
			case ServiceInfoFieldsNames.HOST:
				info.setHost((String) queryResult.get(key));
				break;
			case ServiceInfoFieldsNames.QUEUE_NAME:
				info.setQueueName((String) queryResult.get(key));
				break;
			case ServiceInfoFieldsNames.TIME_STAMP:
				info.setTimestamp((Date) queryResult.get(key));
				break;
			default:
				info.addProperty(key, (String) queryResult.get(key));
				break;
			}
		}
		return info;
	}

	@Override
	public List<String> updateServicesList(List<String> list) {
		ArrayList<String> diffList = new ArrayList<String>();
		DBCursor cursor;
		DBObject queryResult;
		BasicDBObject updater = new BasicDBObject();
		BasicDBObject query = new BasicDBObject();
		// pobranie wszystkich wpisow z kolekcji
		for (String id : list) {
			query.put(ServiceInfoFieldsNames.ID, id);
			cursor = coll.find(query);
			try {
				if (cursor.hasNext()) {
					queryResult = cursor.next();
					id = (String) queryResult.get(ServiceInfoFieldsNames.ID);
					// wpisanie ID aktualnie sprawdzanej uslugi
					updater.put(ServiceInfoFieldsNames.ID, id);
					// uaktualnienie timestampa
					queryResult.put(ServiceInfoFieldsNames.TIME_STAMP, new Date());
					// uaktualnienie wpisu w bazie
					coll.update(updater, queryResult);
				} else {
					diffList.add(id);
				}
			} finally {
				cursor.close();
			}
		}
		return diffList;
	}
}
